package com.tfb.service.utility;

import java.util.Date;
import java.util.List;
import java.util.TimerTask;

import javax.servlet.http.HttpServlet;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.codehaus.jackson.JsonNode;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.tfb.dao.DeviceMapper;
import com.tfb.dao.LocationDataMapper;
import com.tfb.dao.DeviceDataMapper;
import com.tfb.rong.*;
import com.tlr.device.model.EbanUser;
import com.tlr.device.model.LocationCard;
import com.tlr.device.service.AirMeasureDevice;
import com.tlr.device.service.EbanDeviceAPI;
import com.tlr.device.service.LocationDevice;
import java.io.IOException;
import java.text.ParseException;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonGenerator;

public class DeviceTask extends TimerTask {

    private static final Logger log = Logger.getLogger(DeviceTask.class);
    public static final int DEVICE_EBAN = 1;
    public static final int DEVICE_EBAN_LAST_BASIC_INFO = 10;
    public static final int DEVICE_LOCATION = 2;
    public static final int DEVICE_AIRBOX = 3;
    public static final int DEVICE_AIRCLEAN = 4;
    public static final int DATA_PLACE = 1;
    public static final int DATA_WARNING = 2;
    public static final int DATA_JSON_PM25 = 3;
    private final int device_type;
    private final HttpServlet servlet;
    private ApplicationContext applicationct;

    public DeviceTask(HttpServlet hs, ApplicationContext ac) {
        super();
        servlet = hs;
        device_type = DEVICE_AIRBOX;
        applicationct = ac;

    }

    public DeviceTask(HttpServlet hs) {
        super();
        servlet = hs;
        device_type = DEVICE_AIRBOX;
        applicationct = null;

    }

    public DeviceTask(HttpServlet hs, int ntype, ApplicationContext ac) {
        super();
        servlet = hs;
        device_type = ntype;
        applicationct = ac;
    }

    public SqlSession openOneSession() {
        SqlSession session = null;
        try {
            if (applicationct == null && servlet != null) {
                applicationct = WebApplicationContextUtils.getWebApplicationContext(servlet.getServletContext());
            }
            if (applicationct == null) {
                return null;
            }

            SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) applicationct.getBean("sqlSessionFactory");
            session = sqlSessionFactory.openSession();
        } catch (Exception e) {
            log.error("open session fail due to exception " + e);
            session = null;
        }

        return session;
    }

    private void PollAllAirBox() {
        SqlSession session = openOneSession();
        if (session != null) {
            try {
                Device devquery = new Device();
                devquery.setDevicetype(DEVICE_AIRBOX);
                DeviceMapper mapper = session.getMapper(DeviceMapper.class);
                DeviceDataMapper dataMapper = session.getMapper(DeviceDataMapper.class);
                List<Device> dl = mapper.selectAllActiveDevice(devquery);
                log.debug("found aribox " + dl.size());
                AirMeasureDevice airbox = new AirMeasureDevice();
                for (Device device : dl) {
                    System.out.println("now try to get the data for airbox:" + device.getDevicename());
                    JsonNode jn = airbox.getDeviceDataJson(device.getDevicemac(), "PM2.5");
                    if (jn == null) {
                        System.out.println("can't get the json data");
                        continue;
                    }
                    System.out.println("get the data for airbox:" + jn.toString());
                    DeviceDataWithBLOBs data = new DeviceDataWithBLOBs();
                    data.setData(jn.toString());
                    data.setDeviceid(device.getDeviceid());
                    data.setGettime(new Date());
                    dataMapper.insert(data);
                }
            } catch (Exception e) {
                log.error("PollAllAirBox execute selectAllActionDevice fail due to exception " + e);
            } finally {
                session.close();
            }
        }
        // first get all device from database

        // for each device,poll the data and save it into database
        // log poll message
    }

    private void PollAllAirClean() {
        // first get all device from database

        // for each device,poll the data and save it into database
        // log poll message
    }

    private void PollAllEBan() {
        /*
         * //first get all device from database SqlSession session =
         * openOneSession(); if (session != null) { try { DeviceMapper mapper =
         * session.getMapper(DeviceMapper.class); DeviceDataMapper dataMapper =
         * session.getMapper(DeviceDataMapper.class); pollEbanBasicData(mapper,
         * dataMapper); } catch (IOException | ParseException e) { log.error(
         * "PollAllAirBox execute selectAllActionDevice fail due to exception "
         * + e); } finally { session.close(); } } //
         */
        // for each device,poll the data and save it into database
        // log poll message
    }

    @SuppressWarnings("unused")
    private void pollEbanBasicData(DeviceMapper mapper, DeviceDataMapper dataMapper)
    throws IOException, ParseException {
        Device d = new Device();
        d.setDevicetype(DeviceTask.DEVICE_EBAN);
        d.setStatus(1);
        List<Device> devices = mapper.selectDevices(d);
        for (Device device : devices) {
            JsonUtil jsonU = JsonUtil.createJsonUtility();
            JsonGenerator jsonG = jsonU.getGenerator();
            EbanDeviceAPI eban = new EbanDeviceAPI();
            List<EbanUser> users = eban.getUserInfoList(device.getRealname(), device.getDevicepwd(),
                                                        device.getDevicemac());
            if (users.isEmpty()) {
                log.error(String.format("Can't get the eban data for deviceid '%s', devicemac '%s'",
                                        device.getDeviceid(), device.getDevicemac()));
                continue;
            }
            EbanUser user = users.get(0);
            try {
                String date = EbanDeviceAPI.getDayFormat().format(new Date());
                String last = eban.getLastSDay(user.getToken(), device.getDevicemac(), date);
                jsonG.writeStartObject();
                jsonG.writeFieldName("point_data");
                jsonG.writeRawValue(last);
                jsonG.writeFieldName("position_data");
                jsonG.writeRawValue(eban.getLastTrack(user.getToken(), device.getDevicemac(), date));
                jsonG.writeEndObject();
                DeviceDataWithBLOBs dd = new DeviceDataWithBLOBs();
                dd.setDeviceid(device.getDeviceid());
                dd.setData(jsonU.toUTF8String());
                dd.setDatatype(DeviceTask.DEVICE_EBAN_LAST_BASIC_INFO);
                dd.setGettime(new Date());
                // Insert new data
                dataMapper.insertSelective(dd);
                // Remove old data
                dataMapper.deleteDataBefore6Hours(dd);
            } finally {
                eban.logoff(user.getToken());
            }
        }
        log.info("Completed polling eban basic data");
    }

    private void PollAllLocation() {
        SqlSession session = openOneSession();
        if (session != null) {
            try {
                Device devquery = new Device();
                devquery.setDevicetype(DEVICE_LOCATION);
                DeviceMapper mapper = session.getMapper(DeviceMapper.class);
                DeviceDataMapper dataMapper = session.getMapper(DeviceDataMapper.class);
                LocationDataMapper locationMapper = session.getMapper(LocationDataMapper.class);
                List<Device> dl = mapper.selectAllActiveDevice(devquery);
                log.debug("found location card " + dl.size());
                for (Device device : dl) {
                    LocationDevice locationdevice = new LocationDevice();
                    LocationCard lcard = locationdevice.getLocationDevice(device.getEcid(), device.getMsisdn());
                    if (lcard == null) {
                        System.out.println("can't get the LocationCard data for " + device.getDeviceid());
                        continue;
                    }
                    System.out.println("get the data for airbox:" + lcard.getLat() + " long:" + lcard.getLng());
                    DeviceDataWithBLOBs data = new DeviceDataWithBLOBs();
                    data.setLat(lcard.getLat());
                    data.setLng(lcard.getLng());
                    data.setDeviceid(device.getDeviceid());
                    data.setGettime(new Date());
                    dataMapper.insert(data);
                    // insert

                    LocationData ld = new LocationData();
                    ld.setGettime(data.getGettime());
                    ld.setLat(data.getLat());
                    ld.setLng(data.getLng());
                    ld.setDeviceid(data.getDeviceid());
                    locationMapper.insert(ld);
                }

                // delete not used location data
                int ret = locationMapper.deleteOldData();
                log.info("remove old location data return " + ret);
            } catch (Exception e) {
                log.error("PollAllAirBox execute selectAllActionDevice fail due to exception " + e);
            } finally {
                session.close();
            }
        }
        // first get all device from database

        // for each device,poll the data and save it into database
        // log poll message
    }

    @Override
    public void run() {
        log.info("start to fetch data from device for " + device_type);
        switch (device_type) {
            case DEVICE_AIRBOX:
                PollAllAirBox();
                break;
            case DEVICE_AIRCLEAN:
                PollAllAirClean();
                break;
            case DEVICE_EBAN:
                PollAllEBan();
                break;
            case DEVICE_LOCATION:
                PollAllLocation();
                break;
            default:
                log.info("device type is unknown, ignore it!");
                break;
        }
        log.info("end to fetch data from device for " + device_type);
    }

}
